package com.insigma.business.qrcode.common.annotation;

import com.google.common.collect.Lists;

import com.insigma.business.qrcode.soldier.dto.SystemConfigService;
import com.insigma.business.qrcode.soldier.entity.SystemConfigDO;
import com.insigma.business.qrcode.soldier.util.PrivacyEncComponent;
import com.insigma.business.qrcode.soldier.util.PrivacyEncUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;
import java.util.List;


@Slf4j
@Aspect
@Component
public class MybatisCryptAspect {

    private Boolean isCrypted;

    @Autowired
    private SystemConfigService systemConfigService;

    
    @Around("@within(crypt)")
    public Object doAround(ProceedingJoinPoint joinPoint, Crypt crypt) throws Throwable {
        Object[] params = joinPoint.getArgs();
        //系统记录操作的切面功能暂时注释
        if (false) {

            if (isCrypted == null) {
                SystemConfigDO xitongjiami = systemConfigService.getByName("XITONGJIAMI");
                String value = xitongjiami.getValue();
                if (!"true".equals(value)) {
                    isCrypted = false;
                    return joinPoint.proceed(params);
                } else {
                    isCrypted = true;
                }
            }

            if (Boolean.FALSE.equals(isCrypted)) {
                return joinPoint.proceed(params);
            }


            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Class declaringType = methodSignature.getDeclaringType();
            String className = declaringType.getSimpleName();
            if (className.endsWith("Dao")) {
                int dao = className.lastIndexOf("Dao");
                String doClassName = className.substring(0, dao) + "DO";
                String bSearcherClassName = className.substring(0, dao) + "BSearcher";

                Method method = methodSignature.getMethod();
                String methodName = method.getName();

                String idCardNoFieldName = blankToNull(crypt.decryptFields()[0]);
                String mobileFieldName = blankToNull(crypt.decryptFields()[1]);
                String addressFieldName = blankToNull(crypt.decryptFields()[2]);


                Crypt methodAnnotation = methodSignature.getMethod().getAnnotation(Crypt.class);

                encodeParams(params, doClassName, bSearcherClassName, methodName, idCardNoFieldName, mobileFieldName, addressFieldName, methodAnnotation);

                Object result = joinPoint.proceed(params);

                if (result == null) {
                    return result;
                }
                if (result instanceof Long || result instanceof Integer) {
                    return result;
                }

                if (result instanceof String) {
                    if (methodAnnotation != null && methodAnnotation.returnDecrypt()) {
                        if (Strings.isNotBlank(idCardNoFieldName)) {
                            return PrivacyEncUtils.decodeIdCardNo(result.toString());
                        }
                        if (Strings.isNotBlank(mobileFieldName)) {
                            return PrivacyEncUtils.decodeMobile(result.toString());
                        }
                    }
                }

                if (result instanceof List) {
                    List listRes = (List) result;
                    if (listRes.size() > 0) {
                        if (listRes.get(0).getClass().getSimpleName().equals(doClassName)) {
                            PrivacyEncComponent.decodeField(result, idCardNoFieldName, mobileFieldName, addressFieldName);
                        } else if (methodAnnotation != null && methodAnnotation.returnDecrypt()) {
                            if (listRes.get(0).getClass().getSimpleName().equals("String")) {
                                List<String> rsTmp = Lists.newArrayList();
                                for (Object listRe : listRes) {
                                    if (Strings.isNotBlank(idCardNoFieldName)) {
                                        rsTmp.add(PrivacyEncUtils.decodeIdCardNo(listRe.toString()));
                                    } else if (Strings.isNotBlank(mobileFieldName)) {
                                        rsTmp.add(PrivacyEncUtils.decodeMobile(listRe.toString()));
                                    }
                                }
                                result = rsTmp;
                            } else {
                                PrivacyEncComponent.decodeField(result, idCardNoFieldName, mobileFieldName, addressFieldName);
                                if (methodAnnotation.returnDecryptFields().length > 0) {
                                    String idCardNor = blankToNull(methodAnnotation.returnDecryptFields()[0]);
                                    String mobiler = blankToNull(methodAnnotation.returnDecryptFields()[1]);
                                    String addressr = blankToNull(methodAnnotation.returnDecryptFields()[2]);
                                    PrivacyEncComponent.decodeField(result, idCardNor, mobiler, addressr);
                                }
                            }
                        }
                    }
                }

                if (result.getClass().getSimpleName().equals(doClassName)) {
                    PrivacyEncComponent.decodeField(result, idCardNoFieldName, mobileFieldName, addressFieldName);
                }

                return result;
            }
        }
        return joinPoint.proceed(params);
    }

    private void encodeParams(Object[] params, String doClassName, String bSearcherClassName, String methodName, String idCardNoFieldName, String mobileFieldName, String addressFieldName, Crypt methodAnnotation) {
        
        if (methodName.startsWith("search")) {
            if (params.length == 1) {
                Object param = params[0];
                if (param.getClass().getSimpleName().equals(bSearcherClassName)) {
                    PrivacyEncComponent.encodeSearchField(param, idCardNoFieldName, mobileFieldName, addressFieldName);
                } else {
                    
                }
            } else {
                
            }
            return;
        }

        if (methodName.startsWith("insert") || methodName.startsWith("update")) {
            if (params.length == 1) {
                Object param = params[0];
                if (param.getClass().getSimpleName().equals(doClassName)) {
                    PrivacyEncComponent.encodeField(param, idCardNoFieldName, mobileFieldName, addressFieldName);
                } else {
                    
                }
            } else {
                
            }
            return;
        }

        
        if (methodAnnotation != null && methodAnnotation.encryptParamIndex().length != 0) {
            
            Object param = params[methodAnnotation.encryptParamIndex()[0]];
            if (!param.getClass().getSimpleName().equals("String")) {
                
                if (param instanceof List) {
                    
                    List paramList = (List) param;
                    if (!CollectionUtils.isEmpty(paramList)) {
                        Object o = paramList.get(0);
                        if (o instanceof String) {
                            List<String> paramEncList = Lists.newArrayList();
                            for (Object o1 : paramList) {
                                if (Strings.isNotBlank(idCardNoFieldName)) {
                                    paramEncList.add(PrivacyEncUtils.encodeIdCardNo(o1.toString()));
                                }
                                if (Strings.isNotBlank(mobileFieldName)) {
                                    paramEncList.add(PrivacyEncUtils.encodeMobile(o1.toString()));
                                }
                            }
                            param = paramEncList;
                        }
                    }
                } else {
                    PrivacyEncComponent.encodeField(param, idCardNoFieldName, mobileFieldName, addressFieldName);
                }
            } else {
                if (Strings.isNotBlank(idCardNoFieldName)) {
                    param = PrivacyEncUtils.encodeCharByIdCardNo(param.toString());
                }
                if (Strings.isNotBlank(mobileFieldName)) {
                    param = PrivacyEncUtils.encodeMobile(param.toString());
                }
            }
            params[methodAnnotation.encryptParamIndex()[0]] = param;
            return;
        }

        if (methodAnnotation != null) {
            if (params.length == 1) {
                Object param = params[0];
                if (!param.getClass().getSimpleName().equals("String")) {
                    
                    if (param instanceof List) {
                        
                        List paramList = (List) param;
                        if (!CollectionUtils.isEmpty(paramList)) {
                            Object o = paramList.get(0);
                            if (o instanceof String) {
                                List<String> paramEncList = Lists.newArrayList();
                                for (Object o1 : paramList) {
                                    if (Strings.isNotBlank(idCardNoFieldName)) {
                                        paramEncList.add(PrivacyEncUtils.encodeIdCardNo(o1.toString()));
                                    }
                                    if (Strings.isNotBlank(mobileFieldName)) {
                                        paramEncList.add(PrivacyEncUtils.encodeMobile(o1.toString()));
                                    }
                                }
                                param = paramEncList;
                            }
                        }
                    } else {
                        PrivacyEncComponent.encodeField(param, idCardNoFieldName, mobileFieldName, addressFieldName);
                    }
                } else {
                    
                    if (Strings.isNotBlank(idCardNoFieldName)) {
                        param = PrivacyEncUtils.encodeCharByIdCardNo(param.toString());
                    }
                    if (Strings.isNotBlank(mobileFieldName)) {
                        param = PrivacyEncUtils.encodeMobile(param.toString());
                    }
                }
                params[0] = param;
            } else {
                
            }

            return;
        }
    }

    private String blankToNull(String str) {
        if (Strings.isBlank(str)) {
            return null;
        }
        return str.trim();
    }

    public void setCrypted(Boolean crypted) {
        isCrypted = crypted;
    }
}
